<template>
	<view class="module-list y-flex-1" ref="moduleList">
		<com-list
		:data-id="dataId"
		ref="list"
		:bounce="bounce"
		:back-top-show="backTopShow"
		:refreshImage="refreshImage"
		:pulldownable="pulldownable"
		enable-scroll-event
		class="y-flex-1"
		@scroll="handleScroll"
		@pulldown="handlePulldown"
		@loadmore="handleLoadmore">
			<slot name="top"></slot>
			<template v-for="component in components">
				<cell v-if="component.data || ['search-input', 'title'].includes(component.name)">
					<component
					:data="component.data"
					:is="'find-' + component.name"
					:options="component.style"
					:border-radius="component.cellStyle['border-radius']"
					:bg-color="component.cellStyle['background-color']"
					:color="['title'].includes(component.name) ? themeColor : skinColor.color_1"
					:style="{...component.cellStyle,
						//部分组件不能有背景色
						'background-color': ['title', 'links'].includes(component.name) ? '' : component.cellStyle['background-color'],
						//title组件默认加上上间距
						'margin-top': ['title'].includes(component.name) && typeof component.style.marginTop == 'undefined' ? pixelunit(20) : component.cellStyle['margin-top'],
						//title组件默认加上下间距
						'margin-bottom': ['title'].includes(component.name) && typeof component.style.marginBottom == 'undefined' ? pixelunit(20) : component.cellStyle['margin-bottom'],
						//部分组件不能有上下边框
						'border-top': ['title', 'links'].includes(component.name) ? '' : component.cellStyle['border-top'],
						'border-bottom': ['title', 'links'].includes(component.name) ? '' : component.cellStyle['border-bottom']
					}"></component>
				</cell>
			</template>
			<slot name="center"></slot>
			<cell v-if="cellName == 'w-cell'">
				<com-gap :height="cellGap"></com-gap>
			</cell>
			<cell v-if="cellName == 'w-cell'">
				<waterfall :bounce="false" :style="{height: waterfallHeight + 'px'}" ref="waterfall"
				:column-count="cellColumn" column-width="auto"
				:column-gap="unitpixel(cellGap)"
				:left-gap="unitpixel(cellRealStyle['padding-left'])"
				:right-gap="unitpixel(cellRealStyle['padding-right'])"
				@loadmore="handleLoadmore">
					<cell v-for="(item, index) in cells" :key="index">
						<component
						:is="'find-' + cellName"
						:options="cellStyle"
						:item="item"
						:bgColor="cellRealStyle['background-color']"
						:style="{'margin-bottom': pixelunit(cellGap)}"></component>
					</cell>
					<header v-if="loadmoreable || loading">
						<com-loadmore class="mt-30 mb-30" :color="loadingColor" :state="loading ? 'loading' : loadmore" @loadmore="handleLoadmore"></com-loadmore>
					</header>
				</waterfall>
			</cell>
			<template v-else>
			<cell v-for="(grid, i) in Math.ceil(cells.length / cellColumn)">
				<view class="y-flex pt-30 pb-30 border-bottom-1 border-bottom-style-dashed" :style="cellRealStyle">
					<com-grid :data="cells.slice(i * cellColumn, (i + 1) * cellColumn)"
					:column="cellColumn"
					:count="cellColumn"
					:gap="cellGap">
						<template v-slot="{item, index}">
							<component
							:is="'find-' + cellName"
							:options="cellStyle"
							:item="item"></component>
						</template>
					</com-grid>
				</view>
			</cell>
			</template>
			<cell v-if="comments.length > 0">
				<find-title class="mt-20 mb-20"
				:style="{'margin-left': pageMarginGap, 'margin-right': pageMarginGap}"
				title="评论列表" :color="themeColor"></find-title>
			</cell>
			<cell v-for="(item, i) in comments">
				<view class="y-flex pt-30 pb-30 border-bottom-1 border-bottom-style-dashed" :style="cellRealStyle">
					<find-c-cell :item="item" :bgColor="cellRealStyle['background-color']" :options="commentStyle"></find-c-cell>
				</view>
			</cell>
			<cell v-if="(loadmoreable || loading) && cellName != 'w-cell'">
				<com-loadmore class="mt-30 mb-30" :color="loadingColor" :state="loading ? 'loading' : loadmore" @loadmore="handleLoadmore"></com-loadmore>
			</cell>
			<cell v-if="!loadmoreable && cells.length == 0">
				<com-gap></com-gap>
			</cell>
			<slot name="bottom"></slot>
			<template #backTop v-if="backTopImage">
				<image class="backTop" :src="backTopImage" mode="aspectFit"></image>
			</template>
		</com-list>
	</view>	
</template>

<script>
	import { pixelunit, unitpixel, hexToRgba, validateNumber, typeCall, deepClone, isContained } from '@/assets/js/util.js'
	import FindSearchInput from './FindModule/FindSearchInput.vue'
	import FindSlider from './FindModule/FindSlider.vue'
	import FindBanner from './FindModule/FindBanner.vue'
	import FindNoticeBar from './FindModule/FindNoticeBar.vue'
	import FindMenu from './FindModule/FindMenu.vue'
	import FindLink from './FindModule/FindLink.vue'
	import FindLinks from './FindModule/FindLinks.vue'
	import FindCard from './FindModule/FindCard.vue'
	import FindTitle from './FindModule/FindTitle.vue'
	import FindHCell from './FindCell/HCell.vue'
	import FindVCell from './FindCell/VCell.vue'
	import FindImgCell from './FindCell/ImgCell.vue'
	import FindTextCell from './FindCell/TextCell.vue'
	import FindCCell from './FindCell/CCell.vue'
	import FindACell from './FindCell/ACell.vue'
	import FindTCell from './FindCell/TCell.vue'
	import FindWCell from './FindCell/WCell.vue'
	export default {
		inject: ['getPage', 'getSkinColor', 'getSkinMode', 'getComponentStyle', 'getCellStyle', 'getPageStyle', 'getQuery'],
		components:{
			FindSearchInput,
			FindSlider,
			FindBanner,
			FindNoticeBar,
			FindMenu,
			FindLink,
			FindLinks,
			FindCard,
			FindTitle,
			FindHCell,
			FindVCell,
			FindImgCell,
			FindTextCell,
			FindCCell,
			FindACell,
			FindTCell,
			FindWCell
		},
		props: {
			bounce: {
				type: Boolean,
				default: false
			},
			backTopShow: {
				type: Boolean,
				default: false
			},
			refreshImage: {
				type: String,
				default: ''
			},
			pulldownable: {
				type: Boolean,
				default: false
			},
			loadmoreable: {
				type: Boolean,
				default: false
			},
			//是否自定义loadmore
			customloadmore: {
				type: [Object, String],
				default: ''
			},
			backTopImage: {
				type: String,
				default: ''
			},
			loadingColor: {
				type: String,
				default: '#999'
			},
			component: {
				type: Array,
				default () {
					return new Array
				}
			},
			cell: {
				type: Object,
				default () {
					return new Object
				}
			},
			comment: {
				type: Object,
				default () {
					return new Object
				}
			},
			params: {
				type: Object,
				default () {
					return new Object
				}
			}
		},
		computed: {
			pixelunit () {
				return pixelunit
			},
			unitpixel () {
				return unitpixel
			},
			//路由参数
			query () {
				return this.getQuery()
			},
			skinColor () {
				return this.getSkinColor()
			},
			skinMode () {
				return this.getSkinMode()
			},
			pageStyle () {
				return this.getPageStyle()
			},
			componentStyle () {
				return this.getComponentStyle()
			},
			cellRealStyle () {
				const style = Object.assign({}, this.getCellStyle(), this.cellStyle)
				return {
					'margin-left': pixelunit(style.marginLeft),
					'margin-right': pixelunit(style.marginRight),
					'padding-left': pixelunit(style.paddingLeft),
					'padding-right': pixelunit(style.paddingRight),
					'background-color': hexToRgba(style.backgroundColor, style.backgroundOpacity),
					'border-color': this.skinColor.color_gap_1
				}
			},
			pageMarginGap () {
				return pixelunit(this.pageStyle.pageMarginGap)
			},
			network () {
				return this.$store.getters['network/GET']
			},
			commentStyle () {
				return this.comment?.style || {}
			},
			cellStyle () {
				return this.cell?.style || {}
			},
			cellName () {
				return this.cellStyle.cellName || 'h-cell'
			},
			cellColumn () {
				return this.cellStyle.cellColumn || 1
			},
			cellGap () {
				return typeof this.cellStyle.cellGap == 'number' ? this.cellStyle.cellGap : 30
			},
			loadmore () {
				if ( this.customloadmore ) return this.customloadmore?.loadmore || ''
				const type = this.cellPage.loadmore == 'end' ? 'comment' : 'cell'
				return this[type+'Page'].loadmore
			},
			themeColor () {
				return this.pageStyle.themeColor || this.skinColor.color_theme_1
			}
		},
		data () {
			return {
				components: [],
				cells: [],
				comments: [],
				loading: false,
				paramsRecord: {},
				dataId: 'find-module-list' + new Date().getTime(),
				waterfallHeight: 0,
				cellPage: {
					loadmore: '',
					page: 1,
					nextUrl: ''
				},
				commentPage: {
					loadmore: '',
					page: 1,
					nextUrl: ''
				}
			}
		},
		methods: {
			handleScroll (e) {
				this.$emit('scroll', e)
			},
			handlePulldown (callback) {
				this.$emit('pulldown', callback)
			},
			pulldownSuccess () {
				this.$refs.list && this.$refs.list.pulldownSuccess()
			},
			resetLoadmore() {
			    if ( this.cellName == 'w-cell' ) this.$refs.waterfall && this.$refs.waterfall.resetLoadmore()
				else this.$refs.list && this.$refs.list.resetLoadmore()
			},
			backTop () {
				 this.$refs.list && this.$refs.list.backTop()
			},
			setSpecialEffects () {
				if ( this.cellName =='w-cell' ) {
					setTimeout(() => {
						uni.requireNativePlugin('dom').getComponentRect(this.$refs.moduleList, res => {
							this.waterfallHeight = res.size.height
							this.$refs.waterfall && this.$refs.waterfall.setSpecialEffects({id: this.dataId});
						})
					}, 500)
				}
			},
			async initModule (callback, force = false) {
				try{
					if ( force || JSON.stringify(this.params) != JSON.stringify(this.paramsRecord) || (this.components.length == 0 && this.component?.length > 0) || (this.cells.length == 0 && ((this.cell?.request && this.cell?.dynamicData) || (this.cell?.staticData && this.cell?.staticData.length > 0))) ) {
						this.loading = true
						this.paramsRecord = deepClone(this.params)
						this.$refs.list && this.$refs.list.backTop(false)
						this.components = []
						this.cells = []
						this.comments = []
						await this.initComponent()
						//开启了自定义loadmore，暂时不要加载资源和评论列表
						if ( this.customloadmore ) {
							this.cells = []
							this.comments = []
							this.cellPage.page = 1
							this.cellPage.nextUrl = ''
							this.cellPage.loadmore = ''
							this.commentPage.page = 1
							this.commentPage.nextUrl = ''
							this.commentPage.loadmore = ''
							callback('success')
							return
						}
						await this.initMore(callback)
						this.loading = false
					}
					this.$emit('loaded', true)
				}catch(e){
					this.$emit('loaded', true)
					this.loading = false
					callback && callback('fail')
				}
			},
			async initComponent () {
				let comps = []
				const components = this.component ? deepClone(this.component) : []
				const params = Object.assign({}, this.query, this.params)
				const len = components.length
				for ( let i = 0; i < len; i++ ) {
					//如果components属性不为空，则是动态生成组件
					if ( components[i].components && components[i].components.length ) {
						const request = components[i].request
						const newRequest = request ? await this.network.requestHandle(request, params) : null//处理rquest请求
						const response = newRequest ? await this.network.$request(newRequest) : {}//获取内容
						const childComponents = components[i].components
						for ( let j = 0; j < childComponents.length; j++ ) {
							comps = comps.concat(await this.network.$list(childComponents[j], response.data, response.taskId))
						}
					} else {
						components[i].style = components[i].style || {}//组件样式
						components[i].style.themeColor = this.pageStyle.themeColor//获取主题色
						const request = components[i].request
						const newRequest = request ? await this.network.requestHandle(request, params) : null//处理rquest请求
						const response = newRequest ? await this.network.$request(newRequest) : {}//获取内容
						const moreUrl = components[i].style.moreUrl || ''
						if ( moreUrl && response.data ) components[i].style.moreUrl = await this.network.$text(moreUrl, response.data, response.taskId)//处理动态moreUrl
						const staticData = components[i].staticData
						const dynamicData = components[i].dynamicData
						if ( staticData ) components[i].data = await this.network.staticDataHandle(staticData, Object.assign({}, params, {routeUrl: null}))
						if ( dynamicData && response.data ) {
							try{
								if ( dynamicData.subsection ) {
									const subsection = await this.network.$list(dynamicData.subsection, response.data, response.taskId)
									if ( staticData.subsection && staticData.subsection.length ) components[i].data.subsection = staticData.subsection.concat(subsection)
									else components[i].data.subsection = subsection
								}
								if ( dynamicData.list && typeCall(dynamicData.list) == 'Array' ) {
									const list = new Array(dynamicData.list.length)
									for ( let j = 0; j < list.length; j++ ) list[j] = await this.network.$list(dynamicData.list[j], response.data, response.taskId)
									if ( staticData.list && staticData.list.length ) components[i].data.list = staticData.list.concat(list)
									else components[i].data.list = list
								}
								if ( !dynamicData.subsection && (!dynamicData.list || typeCall(dynamicData.list) == 'String') ) {
									const data = await this.network.$list(dynamicData, response.data, response.taskId)
									if ( typeCall(staticData) == 'Array' ) components[i].data = staticData.concat(data)
									else if ( typeCall(staticData) == 'Object' ) components[i].data = Object.assign({}, staticData, data)
									else components[i].data = data
								}
							}catch(e){
								continue
							}
						}
						comps.push(components[i])
					}
				}
				this.components = comps
				this.setComponentStyle()
			},
			//设置组件样式
			setComponentStyle () {
				this.components.forEach(c => {
					const style = Object.assign({}, this.componentStyle, c.style)//公共组件样式混合当前组件样式
					c.cellStyle = {
						'margin-top': pixelunit(style.marginTop),
						'margin-bottom': pixelunit(style.marginBottom),
						'margin-left': pixelunit(style.marginLeft),
						'margin-right': pixelunit(style.marginRight),
						'border-top': this.handleBorder(style.borderTop),
						'border-bottom': this.handleBorder(style.borderBottom),
						'background-color': hexToRgba(style.backgroundColor, style.backgroundOpacity),
						'border-radius': pixelunit(style.borderRadius)
					}//计算渲染的组件样式
				})
			},
			//处理border样式
			handleBorder (border) {
				let str = ''
				const arr = border.toString().split(' ')
				if ( arr.length == 0 || !border ) return str
				for ( let i = 0; i < 3; i++ ) {
					if ( i == 0 ) {
						str += arr[i] ? validateNumber(arr[i]) ? arr[i] + 'px' : arr[i] : '1px'
						str += ' '
					} else if ( i == 1 ) {
						str += arr[i] ? arr[i] : 'solid'
						str += ' '
					} else {
						str += arr[i] ? arr[i] : this.skinColor.color_gap_1
					}
				}
				return str
			},
			//加载更多
			async initMore (callback) {
				await this.initList('cell', callback)
				//加载到列表后，尝试去嵌套列表
				this.$nextTick(() => {
					this.setSpecialEffects()
				})
				//如果cell加载完毕，开始初始化评论列表
				if ( this.cellPage.loadmore == 'end' ) await this.initList('comment')
			},
			/**
			 * 初始化列表数据
			 * @param {String} type cell-资源 comment-评论
			 * @param {Function} callback 外部下拉回调
			*/
			async initList (type, callback) {
				this[type+'Page'].page = 1
				this[type+'Page'].nextUrl = ''
				if ( !callback ) this[type+'Page'].loadmore = ''
				try{
					const list = await this.handleGetList(type)
					this[type+'s'] = list
					callback && callback('success')
					if ( list.length == 0 ) this[type+'Page'].loadmore = 'end'
					else this.resetLoadmore()
				}catch(e){
					this[type+'s'] = []
					this[type+'Page'].loadmore = 'end'
					callback && callback('fail')
				}
			},
			async handleLoadmore () {
				if ( this.customloadmore ) {
					this.$emit('loadmore')
					return
				}
				const type = this.cellPage.loadmore == 'end' ? 'comment' : 'cell'
				if ( ['loading', 'end'].includes(this[type+'Page'].loadmore) || !this.loadmoreable ) return
				this[type+'Page'].loadmore = 'loading'
				this[type+'Page'].page++
				try{
					const list = await this.handleGetList(type)
					if ( !this[type+'Page'].loadmore ) return
					const isCon = isContained(this[type+'s'], list)
					if ( isCon || list.length == 0 ) {
						this[type+'Page'].loadmore = 'end'
					} else {
						this[type+'s'] = this[type+'s'].concat(list)
						this[type+'Page'].loadmore = ''
						this.resetLoadmore()
					}
				}catch(e){
					this[type+'Page'].loadmore = 'end'
				}
				//如果cell加载完毕，开始初始化评论列表
				if ( type == 'cell' && this[type+'Page'].loadmore == 'end' ) this.initList('comment')
			},
			/**
			 * 获取列表数据
			 * @param {String} type 数据类型 cell-资源列表 comment-评论列表
			*/
			async handleGetList (type) {
				const params = Object.assign({}, this.query, this.params, {page: this[type+'Page'].page, list: this[type + 's']})
				const request = this[type].request
				const staticData = this[type].staticData ? await this.network.staticDataHandle(this[type].staticData, params) : []
				const dynamicData = this[type].dynamicData
				let list = []
				if ( request && dynamicData ) {
					const newRequest = await this.network.requestHandle(request, params)
					const response = request ? await this.network.$request(this[type+'Page'].nextUrl ? Object.assign({}, newRequest, {url: this[type+'Page'].nextUrl}) : newRequest) : {}
					this[type+'Page'].nextUrl = newRequest.nextUrl ? await this.network.$text(newRequest.nextUrl, response.data, response.taskId) : ''
					if ( response.data ) list = await this.network.$list(dynamicData, response.data, response.taskId)
				}
				return staticData.concat(list)
			}
		},
		watch: {
			cellName (newVal) {
				this.$nextTick(() => {
					this.setSpecialEffects()
				})
			},
			skinMode () {
				this.setComponentStyle()
			}
		}
	}
</script>

<style>
	.box {
		padding: 30rpx 30rpx 10rpx 30rpx;
		margin: 0 30rpx 30rpx 30rpx;
		border-radius: 20rpx;
	}
	.backTop {
		width: 100rpx;
		height: 100rpx;
	}
</style>
